﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;

namespace Infrastructure.Cache
{
    /// <summary>
    /// 内存缓存管理器（基于 IMemoryCache 实现）
    /// 提供对内存缓存的统一操作封装，支持多种过期策略
    /// </summary>
    public class MemoryCacheManager : ICacheManager
    {
        // 依赖注入的内存缓存实例
        protected IMemoryCache _cache;

        /// <summary>
        /// 构造函数（依赖注入 IMemoryCache）
        /// </summary>
        /// <param name="cache">内存缓存实例</param>
        public MemoryCacheManager(IMemoryCache cache)
        {
            _cache = cache;
        }

        /// <summary>
        /// 检查缓存项是否存在
        /// </summary>
        /// <param name="key">缓存键</param>
        /// <returns>存在返回 true，否则 false</returns>
        public bool Exists(string key)
        {
            if (key == null)
            {
                throw new ArgumentNullException("key");
            }
            // 尝试获取缓存值（不实际取出值）
            return _cache.TryGetValue(key, out _);
        }

        /// <summary>
        /// 添加缓存项（永不过期）
        /// </summary>
        /// <returns>添加成功返回 true</returns>
        public bool Add(string key, object value)
        {
            // 参数校验
            if (key == null) throw new ArgumentNullException(nameof(key));
            if (value == null) throw new ArgumentNullException(nameof(value));

            _cache.Set(key, value);
            return Exists(key); // 二次验证确保添加成功
        }

        /// <summary>
        /// 添加缓存项（同时设置滑动和绝对过期时间）
        /// 注意：实际过期时间以两者中先到达的为准
        /// </summary>
        public bool Add(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte)
        {
            if (key == null) throw new ArgumentNullException(nameof(key));
            if (value == null) throw new ArgumentNullException(nameof(value));

            // 创建混合过期策略配置
            var options = new MemoryCacheEntryOptions()
                .SetSlidingExpiration(expiresSliding)  // 滑动过期（最后一次访问后持续时间）
                .SetAbsoluteExpiration(expiressAbsoulte); // 绝对过期（固定时间点）

            _cache.Set(key, value, options);
            return Exists(key);
        }

        /// <summary>
        /// 添加缓存项（灵活过期策略）
        /// </summary>
        /// <param name="isSliding">
        /// true: 滑动过期（每次访问重置计时）
        /// false: 绝对过期（固定时间间隔）
        /// </param>
        public bool Add(string key, object value, TimeSpan expiresIn, bool isSliding = false)
        {
            if (key == null) throw new ArgumentNullException(nameof(key));
            if (value == null) throw new ArgumentNullException(nameof(value));

            var options = new MemoryCacheEntryOptions();
            if (isSliding)
            {
                options.SetSlidingExpiration(expiresIn);
            }
            else
            {
                options.SetAbsoluteExpiration(expiresIn);
            }

            _cache.Set(key, value, options);
            return Exists(key);
        }

        /// <summary>
        /// 移除指定缓存项
        /// </summary>
        /// <returns>移除成功返回 true</returns>
        public bool Remove(string key)
        {
            if (key == null) throw new ArgumentNullException(nameof(key));

            _cache.Remove(key);
            return !Exists(key); // 验证是否已移除
        }

        /// <summary>
        /// 批量移除缓存项
        /// </summary>
        public void RemoveAll(IEnumerable<string> keys)
        {
            if (keys == null) throw new ArgumentNullException(nameof(keys));

            // 遍历移除每个键（注意：ToList() 防止迭代器延迟执行问题）
            foreach (var item in keys.ToList())
            {
                _cache.Remove(item);
            }
        }

        /// <summary>
        /// 获取缓存项（泛型版本）
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <returns>如果类型不匹配或不存在返回 null</returns>
        public T Get<T>(string key) where T : class
        {
            if (key == null) throw new ArgumentNullException(nameof(key));
            return _cache.Get(key) as T; // 类型安全转换
        }

        /// <summary>
        /// 获取缓存项（非泛型版本）
        /// </summary>
        public object Get(string key)
        {
            if (key == null) throw new ArgumentNullException(nameof(key));
            return _cache.Get(key);
        }

        /// <summary>
        /// 批量获取缓存项
        /// 注意：不存在的键会在字典中存储 null 值
        /// </summary>
        public IDictionary<string, object> GetAll(IEnumerable<string> keys)
        {
            if (keys == null) throw new ArgumentNullException(nameof(keys));

            var dict = new Dictionary<string, object>();
            foreach (var item in keys.ToList())
            {
                dict.Add(item, _cache.Get(item));
            }
            return dict;
        }

        /// <summary>
        /// 替换缓存项（先删除旧值再添加新值）
        /// 注意：非原子操作，可能存在竞态条件
        /// </summary>
        public bool Replace(string key, object value)
        {
            // 参数校验已在 Remove 和 Add 方法中处理
            if (Exists(key) && !Remove(key)) return false;
            return Add(key, value);
        }
        public bool Replace(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte)
        {
            if (key == null) throw new ArgumentNullException("key");

            if (value == null) throw new ArgumentNullException("value");
    
            if (Exists(key) && !Remove(key)) return false;
   
            return Add(key, value, expiresSliding, expiressAbsoulte);
        }

        public bool Replace(string key, object value, TimeSpan expiresIn, bool isSliding = false)
        {
            if (key == null) throw new ArgumentNullException("key");
        
            if (value == null) throw new ArgumentNullException("value");
       
            if (Exists(key) && !Remove(key)) return false;
            return Add(key, value, expiresIn, isSliding);
        }
        // 其他 Replace 重载方法（注释类似，省略重复部分）

        /// <summary>
        /// 释放资源（实现 IDisposable 接口）
        /// </summary>
        public void Dispose()
        {
            _cache?.Dispose();  // 释放缓存实例
            GC.SuppressFinalize(this); // 防止重复调用析构
        }
    }
}
